home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  62.7 KB  |  2,643 lines

  1. /* Main program for the Midnight Commander
  2.    Copyright (C) 1994, 1995 The Free Software Foundation
  3.    
  4.    Written by: 1994, 1995 Miguel de Icaza
  5.                1994, 1995 Janne Kukonlehto
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #include <config.h>
  22. #ifdef _OS_NT
  23. #    include <windows.h>
  24. #    define baudrate 19200
  25. #endif
  26.  
  27. #include "tty.h"
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <sys/types.h>
  32. #include <sys/param.h>
  33.  
  34. #include <sys/stat.h>
  35. #include <sys/types.h>
  36.  
  37. #ifdef HAVE_UNISTD_H
  38. #   include <unistd.h>
  39. #endif
  40.  
  41. /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
  42. #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
  43. #   include <dirent.h>
  44. #   define NLENGTH(dirent) (strlen ((dirent)->d_name))
  45. #else
  46. #   define dirent direct
  47. #   define NLENGTH(dirent) ((dirent)->d_namlen)
  48.  
  49. #   ifdef HAVE_SYS_NDIR_H
  50. #       include <sys/ndir.h>
  51. #   endif /* HAVE_SYS_NDIR_H */
  52.  
  53. #   ifdef HAVE_SYS_DIR_H
  54. #       include <sys/dir.h>
  55. #   endif /* HAVE_SYS_DIR_H */
  56.  
  57. #   ifdef HAVE_NDIR_H
  58. #       include <ndir.h>
  59. #   endif /* HAVE_NDIR_H */
  60. #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
  61.  
  62. #if HAVE_SYS_WAIT_H
  63. #   include <sys/wait.h>    /* For waitpid() */
  64. #endif
  65.  
  66. #include <errno.h>
  67. #include <pwd.h>
  68. #include <ctype.h>
  69. #include <fcntl.h>    /* For O_RDWR */
  70. #include <signal.h>
  71.  
  72. /* Program include files */
  73. #include "mad.h"
  74. #include "dir.h"
  75. #include "color.h"
  76. #include "global.h"
  77. #include "util.h"
  78. #include "dialog.h"
  79. #include "menu.h"
  80. #include "file.h"
  81. #include "panel.h"
  82. #include "main.h"
  83. #include "win.h"
  84. #include "user.h"
  85. #include "mem.h"
  86. #include "mouse.h"
  87. #include "option.h"
  88. #include "tree.h"
  89. #include "cons.saver.h"
  90. #include "subshell.h"
  91. #include "key.h"    /* For init_key() and mi_getch() */
  92. #include "setup.h"    /* save_setup() */
  93. #include "profile.h"    /* free_profiles() */
  94. #include "boxes.h"
  95. #include "layout.h"
  96. #include "cmd.h"        /* Normal commands */
  97. #include "hotlist.h"
  98. #include "panelize.h"
  99. #include "learn.h"
  100. #include "listmode.h"
  101.  
  102. /* Listbox for the command history feature */
  103. #include "widget.h"
  104. #include "command.h"
  105. #include "wtools.h"
  106. #include "complete.h"        /* For the free_completion */
  107.  
  108. #include "chmod.h"
  109. #include "chown.h"
  110.  
  111. #include "../vfs/vfs.h"
  112. #include "../vfs/extfs.h"
  113.  
  114. #ifdef HAVE_XVIEW
  115. #   include "../xv/xvmain.h"
  116. #endif
  117.  
  118. #ifndef MAP_FILE
  119. #define MAP_FILE 0
  120. #endif
  121.  
  122. #ifndef USE_VFS
  123. #ifdef USE_NETCODE
  124. #undef USE_NETCODE
  125. #endif
  126. #endif
  127.  
  128. /* "$Id: main.c,v 1.23 1995/02/21 19:06:29 miguel Exp $" */
  129.  
  130. /* When the modes are active, left_panel, right_panel and tree_panel */
  131. /* Point to a proper data structure.  You should check with the functions */
  132. /* get_current_type and get_other_type the types of the panels before using */
  133. /* This pointer variables */
  134.  
  135. /* The structures for the panels */
  136. WPanel *left_panel;
  137. WPanel *right_panel;
  138.  
  139. /* The pointer to the tree */
  140. WTree *the_tree;
  141.  
  142. /* The Menubar */
  143. WMenu *the_menubar;
  144.  
  145. /* Pointers to the selected and unselected panel */
  146. WPanel *current_panel = NULL;
  147.  
  148. /* Set when we want use advanced chmod command instead of chmod and/or chown */
  149. int advanced_chfns = 0;
  150.  
  151. /* Set when main loop should be terminated */
  152. volatile int quit = 0;
  153.  
  154. /* Set if you want the possible completions dialog for the first time */
  155. int show_all_if_ambiguous = 0;
  156.  
  157. /* Set when cd symlink following is desirable (bash mode) */
  158. int cd_symlinks = 1;
  159.  
  160. /* If set then dialogs just clean the screen when refreshing, else */
  161. /* they do a complete refresh, refreshing all the parts of the program */
  162. int fast_refresh = 0;
  163.  
  164. /* If true, marking a files moves the cursor down */
  165. int   mark_moves_down = 1;
  166.  
  167. /* If true, at startup the user-menu is invoked */
  168. int   auto_menu = 0;
  169.  
  170. /* If true, use + and \ keys normally and select/unselect do if M-+ / M-\ and M--
  171.    and keypad + / - */
  172. int   alternate_plus_minus = 0;
  173.  
  174. /* If true, then the +, - and \ keys have their special meaning only if the
  175.  * command line is emtpy, otherwise they behave like regular letters
  176.  */
  177. int   only_leading_plus_minus = 1;
  178.  
  179. /* If true, after executing a command, wait for a keystroke */
  180. enum { pause_never, pause_on_dumb_terminals, pause_always };
  181.  
  182. int   pause_after_run = pause_on_dumb_terminals;
  183.  
  184. /* It true saves the setup when quitting */
  185. int auto_save_setup = 0;
  186.  
  187. /* If true, be eight bit clean */
  188. int eight_bit_clean = 0;
  189.  
  190. /* If true, then display chars 0-255, else iso-8859-1,
  191.    requires eight_bit_clean */
  192. int full_eight_bits = 0;
  193.  
  194. /* If true use the internal viewer */
  195. int use_internal_view = 1;
  196.  
  197. /* Have we shown the fast-reload warning in the past? */
  198. int fast_reload_w = 0;
  199.  
  200. /* Move page/item? When clicking on the top or bottom of a panel */
  201. int mouse_move_pages = 1;
  202.  
  203. /* If true: l&r arrows are used to chdir if the input line is empty */
  204. int navigate_with_arrows = 0;
  205.  
  206. /* If it is set, the commander will iconify itself when executing a program */
  207. int iconify_on_exec = 1;
  208.  
  209. /* The prompt */
  210. char *prompt = 0;
  211.  
  212. /* The widget where we draw the prompt */
  213. WLabel *the_prompt;
  214.  
  215. /* The hint bar */
  216. WLabel *the_hint;
  217.  
  218. /* The button bar */
  219. WButtonBar *the_bar;
  220. #ifdef HAVE_X
  221. WButtonBar *the_bar2;
  222. #endif
  223.  
  224. /* For slow terminals */
  225. int slow_terminal = 0;
  226.  
  227. /* use mouse? */
  228. int use_mouse_p = GPM_MOUSE;
  229.  
  230. /* If true, assume we are running on an xterm terminal */
  231. static int force_xterm = 0;
  232.  
  233. /* Controls screen clearing before an exec */
  234. int clear_before_exec = 1;
  235.  
  236. /* Asks for confirmation before deleting a file */
  237. int confirm_delete = 1;
  238.  
  239. /* Asks for confirmation before overwriting a file */
  240. int confirm_overwrite = 1;
  241.  
  242. /* Asks for confirmation before leaving the program */
  243. int confirm_exit = 1;
  244.  
  245. /* Asks for confirmation when using F3 to view a directory and there
  246.    are tagged files */
  247. int confirm_view_dir = 0;
  248.  
  249. /* This flag is set by xterm detection routine in function main() */
  250. /* It is used by function view_other_cmd() */
  251. int xterm_flag = 0;
  252.  
  253. /* This flag indicates if the pull down menus by default drop down */
  254. int drop_menus = 0;
  255.  
  256. /* The dialog handle for the main program */
  257. Dlg_head *midnight_dlg;
  258.  
  259. /* Subshell: if set, then the prompt was not saved on CONSOLE_SAVE */
  260. /* We need to paint it after CONSOLE_RESTORE, see: load_prompt */
  261. int update_prompt = 0;
  262.  
  263. /* The home directory */
  264. char *home_dir;
  265.  
  266. /* The value of the other directory, only used when loading the setup */
  267. char *other_dir = 0;
  268. char *this_dir = 0;
  269.  
  270. /* If true, then print on stdout the last directory we were at */
  271. static int print_last_wd = 0;
  272. static char *last_wd_string;
  273. static int print_last_revert = 0;
  274.  
  275. /* widget colors for the midnight commander */
  276. int midnight_colors [4];
  277.  
  278. /* Force colors, only used by Slang */
  279. int force_colors = 0;
  280.  
  281. /* colors specified on the command line: they override any other setting */
  282. char *command_line_colors;
  283.  
  284. /* File name to view if argument was supplied */
  285. char *view_one_file = 0;
  286.  
  287. /* Used so that widgets know if they are being destroyed or
  288.    shut down */
  289. int midnight_shutdown = 0;
  290.  
  291. /* to show nice prompts */
  292. static int last_paused = 0;
  293.  
  294. /* Only used at program boot */
  295. int boot_current_is_left = 1;
  296.  
  297. /* Ugly hack in order to distinguish between left and right panel in menubar */
  298. int is_right;
  299. #define MENU_PANEL_IDX  (is_right ? 1 : 0)
  300.  
  301. char cmd_buf [512];
  302.  
  303. static void save_setup_cmd (void);
  304. static void menu_cmd (void);
  305.  
  306. static const int status_mouse_support = 
  307. #ifdef HAVE_LIBGPM
  308.     1;
  309. #else
  310.     0;
  311. #endif
  312.  
  313. const int status_using_ncurses =
  314. #ifdef HAVE_SLANG
  315.     0;
  316. #else
  317. #ifdef USE_NCURSES
  318.     1;
  319. #else
  320.     0;
  321. #endif
  322. #endif
  323.  
  324. static const int status_using_old_tools =
  325. #ifdef OLD_TOOLS
  326.     1;
  327. #else
  328.     0;
  329. #endif
  330.  
  331. int panel_event    (Gpm_Event *event, WPanel *panel);
  332. int menu_bar_event (Gpm_Event *event, void *);
  333.  
  334. void try_to_select (WPanel *panel, char *name)
  335. {
  336.     Xtry_to_select (panel, name);
  337.     select_item (panel);
  338.     display_mini_info (panel);
  339. }
  340.  
  341. /* If we moved to the parent directory move the selection pointer to
  342.    the old directory name */
  343. void cd_try_to_select (WPanel *panel)
  344. {
  345.     char *p, *q;
  346.     int i, j = 4;
  347.  
  348.     if (strlen (panel->lwd) > strlen (panel->cwd)
  349.     && strncmp (panel->cwd, panel->lwd, strlen (panel->cwd)) == 0
  350.     && strchr (panel->lwd + strlen (panel->cwd) + 1, PATH_SEP) == 0)
  351.     try_to_select (panel, panel->lwd);
  352.     else
  353. #ifdef USE_VFS
  354.     if ((!strncmp (panel->lwd, "tar:", 4) && 
  355.              !strncmp (panel->lwd + 4, panel->cwd, strlen (panel->cwd))) ||
  356.              ((i = extfs_prefix_to_type (panel->lwd)) != -1 && 
  357.              !strncmp (panel->lwd + (j = strlen (extfs_get_prefix (i)) + 1), 
  358.              panel->cwd, strlen (panel->cwd)))) {
  359.         p = strdup (panel->lwd + j + strlen (panel->cwd));
  360.         q = strchr (p, PATH_SEP);
  361.         if (q != NULL && (q != p || (q = strchr (q + 1, PATH_SEP)) != NULL))
  362.             *q = 0;
  363.         try_to_select (panel, p);
  364.         free (p);
  365.     } else
  366. #endif
  367.     try_to_select (panel, NULL);
  368. }
  369.  
  370. void reload_panelized (WPanel *panel)
  371. {
  372.     int i, j;
  373.     dir_list *list = &panel->dir;
  374.     
  375.     if (panel != current_panel)
  376.     mc_chdir (panel->cwd);
  377.     
  378.     for (i = 0, j = 0; i < panel->count; i++){
  379.     if (mc_lstat (list->list [i].fname, &list->list [i].buf))
  380.         continue;
  381.     if (j != i)
  382.         list->list [j] = list->list [i];
  383.     j++;
  384.     }
  385.     if (j == 0)
  386.     panel->count = set_zero_dir (list);
  387.     else {
  388.     for (i = j; i < panel->count; i++){
  389.         free (list->list [i].fname);
  390.     }
  391.     panel->count = j;
  392.     }
  393.     if (panel != current_panel)
  394.     mc_chdir (current_panel->cwd);
  395. }
  396.  
  397. void update_one_panel (int which, int force_update, char *current_file)
  398. {
  399.     int free_pointer;
  400.     WPanel *panel;
  401.  
  402.     if (get_display_type (which) != view_listing)
  403.     return;
  404.  
  405.     panel = (WPanel *) get_panel_widget (which);
  406.  
  407.     if (force_update & UP_RELOAD){
  408.     panel->is_panelized = 0;
  409.  
  410.     ftpfs_flushdir ();
  411.     bzero (&(panel->dir_stat), sizeof (panel->dir_stat));
  412.     }
  413.     /* If current_file == -1 (an invalid pointer) then preserve selection */
  414.     if (current_file == UP_KEEPSEL){
  415.     free_pointer = 1;
  416.     current_file = strdup (panel->dir.list [panel->selected].fname);
  417.     } else
  418.     free_pointer = 0;
  419.     
  420.     if (panel->is_panelized)
  421.     reload_panelized (panel);
  422.     else
  423.     panel_reload (panel);
  424.  
  425.     try_to_select (panel, current_file);
  426.     panel->dirty = 1;
  427.  
  428.     if (free_pointer)
  429.     free (current_file);
  430. }
  431.  
  432. /* This routine reloads the directory in both panels. It tries to
  433. ** select current_file in current_panel and other_file in other_panel.
  434. ** If current_file == -1 then it automatically sets current_file and
  435. ** other_file to the currently selected files in the panels.
  436. **
  437. ** if force_update has the UP_ONLY_CURRENT bit toggled on, then it
  438. ** will not reload the other panel.
  439. */
  440. void update_panels (int force_update, char *current_file, char *other_file)
  441. {
  442.     int reload_other = !(force_update & UP_ONLY_CURRENT);
  443.     WPanel *panel;
  444.     
  445.     update_one_panel (get_current_index (), force_update, current_file);
  446.     if (reload_other)
  447.     update_one_panel (get_other_index (), force_update, other_file);
  448.  
  449.     if (get_current_type () == view_listing)
  450.     panel = (WPanel *) get_panel_widget (get_current_index ());
  451.     else
  452.     panel = (WPanel *) get_panel_widget (get_other_index ());
  453.  
  454.     mc_chdir (panel->cwd);
  455. }
  456.  
  457. #ifdef WANT_PARSE
  458. static void select_by_index (WPanel *panel, int i);
  459.  
  460. /* Called by parse_control_file */
  461. static int index_by_name (file_entry *list, int count)
  462. {
  463.     char *name;
  464.     int i;
  465.  
  466.     name = strtok (NULL, " \t\n");
  467.     if (!name || !*name)
  468.     return -1;
  469.     for (i = 0; i < count; i++){
  470.     if (strcmp (name, list[i].fname) == 0)
  471.         return i;
  472.     }
  473.     return -1;
  474. }
  475.  
  476. /* Called by parse_control_file */
  477. static void select_by_index (WPanel *panel, int i)
  478. {
  479.     if (i >= panel->count)
  480.     return;
  481.     
  482.     unselect_item (panel);
  483.     panel->selected = i;
  484.  
  485. #ifndef HAVE_X    
  486.     while (panel->selected - panel->top_file >= ITEMS (panel)){
  487.     /* Scroll window half screen */
  488.     panel->top_file += ITEMS (panel)/2;
  489.     paint_dir (panel);
  490.     select_item (panel);
  491.     } 
  492.     while (panel->selected < panel->top_file){
  493.     /* Scroll window half screen */
  494.     panel->top_file -= ITEMS (panel)/2;
  495.     if (panel->top_file < 0) panel->top_file = 0;
  496.     paint_dir (panel);
  497.     } 
  498. #endif
  499.     select_item (panel);
  500. }
  501.  
  502. /* Called by my_system
  503.    No error reporting, just exits on the first sign of trouble */
  504. static void parse_control_file (void)
  505. {
  506.     char *data, *current;
  507.     WPanel *panel;
  508.     file_entry *list;
  509.     int i;
  510.     FILE *file;
  511.     struct stat s;
  512.     
  513.     if ((file = fopen (control_file, "r")) == NULL){
  514.     return;
  515.     }
  516.     /* Use of fstat prevents race conditions */
  517.     if (fstat (fileno (file), &s) != 0){
  518.     fclose (file);
  519.     return;
  520.     }
  521. #ifndef _OS_NT
  522.     /* Security: Check that the user owns the control file to prevent
  523.        other users from playing tricks on him/her. */
  524.     if (s.st_uid != getuid ()){
  525.     fclose (file);
  526.     return;
  527.     }
  528. #endif
  529.     data = (char *) xmalloc (s.st_size+1, "main, parse_control_file");
  530.     if (!data){
  531.     fclose (file);
  532.     return;
  533.     }
  534.     if (s.st_size != fread (data, 1, s.st_size, file)){
  535.     free (data);
  536.     fclose (file);
  537.     return;
  538.     }
  539.     data [s.st_size] = 0;
  540.     fclose (file);
  541.     
  542.     /* The Control file has now been loaded to memory -> start parsing. */
  543.     current = strtok (data, " \t\n");
  544.     while (current && *current){
  545.     if (isupper (*current)){
  546.         if (get_other_type () != view_listing)
  547.         break;
  548.         else
  549.         panel = other_panel;
  550.     } else
  551.         panel = current_panel;
  552.  
  553.     list = panel->dir.list;
  554.     *current = tolower (*current);
  555.  
  556.     if (strcmp (current, "clear_tags") == 0){
  557.         panel->marked = 0;
  558.         panel->total = 0;
  559.         panel->dirs_marked = 0;
  560.         for (i = 0; i < panel->count; i++)
  561.         file_mark (list, i, 0);
  562.  
  563.     } else if (strcmp (current, "tag") == 0){
  564.         i = index_by_name (list, panel->count);
  565.         if (i >= 0 && ! list[i].f.marked){
  566.         file_mark (panel, i, 1);
  567.         if (S_ISDIR (list[i].buf.st_mode))
  568.             panel->dirs_marked++;
  569.         panel->marked++;
  570.         panel->total += list[i].buf.st_size;
  571.         }
  572.     } else if (strcmp (current, "untag") == 0){
  573.         i = index_by_name (list, panel->count);
  574.         if (i >= 0 && list[i].f.marked){
  575.         set_mark (panel, i, 0);
  576.         if (S_ISDIR (list[i].buf.st_mode))
  577.             panel->dirs_marked--;
  578.         panel->marked--;
  579.         panel->total -= list[i].buf.st_size;
  580.         }
  581.     } else if (strcmp (current, "select") == 0){
  582.         i = index_by_name (list, panel->count);
  583.         if (i >= 0){
  584.         select_by_index (panel, i);
  585.         }
  586.     } else if (strcmp (current, "change_panel") == 0){
  587.         change_panel ();
  588.     } else if (strcmp (current, "cd") == 0){
  589.         int change = 0;
  590.         current = strtok (NULL, " \t\n");
  591.         if (!current) break;
  592.         if (cpanel != panel){
  593.         change_panel ();
  594.         change = 1;
  595.         }
  596.         do_cd (current);
  597.         if (change)
  598.         change_panel ();
  599.     } else {
  600.         /* Unknown command -> let's give up */
  601.         break;
  602.     }
  603.     current = strtok (NULL, " \t\n");
  604.     }
  605.  
  606.     free (data);
  607.     paint_panel (cpanel);
  608.     paint_panel (opanel);
  609. }
  610. #endif
  611.  
  612. void clr_scr (void)
  613. {
  614.     standend ();
  615.     dlg_erase (midnight_dlg);
  616.     refresh ();
  617.     doupdate ();
  618. }
  619.  
  620. /* Sets up the terminal before executing a program */
  621. static void pre_exec (void)
  622. {
  623.     use_dash (0);
  624.     if (clear_before_exec)
  625.     clr_scr ();
  626.     else {
  627.     if (!(console_flag || xterm_flag))
  628.         printf ("\n\n");
  629.     }
  630.  
  631. #ifdef HAVE_TK
  632.     if (iconify_on_exec)
  633.     tk_evalf ("wm iconify .");
  634. #endif
  635. #ifndef HAVE_X
  636.     channels_down ();
  637.     if (use_mouse_p)
  638.     shut_mouse ();
  639.  
  640.     reset_shell_mode ();
  641.     keypad (stdscr, FALSE);
  642.     endwin ();
  643.  
  644.     if (alternate_plus_minus && (console_flag || xterm_flag)) {
  645.         fprintf (stderr, "\033>"); fflush (stderr);
  646.     }
  647.         
  648.     /* on xterms: maybe endwin did not leave the terminal on the shell
  649.      * screen page: do it now.
  650.      *
  651.      * Do not move this before endwin: in some systems rmcup includes
  652.      * a call to clear screen, so it will end up clearing the sheel screen.
  653.      */
  654.     if (!status_using_ncurses){
  655.     do_exit_ca_mode ();
  656.     }
  657. #endif /* HAVE_X */
  658. }
  659.  
  660. /* Restores the terminal after an exec, see execute for extra post-exec code */
  661. static void post_exec (void)
  662. {
  663. #ifndef HAVE_X
  664.     do_enter_ca_mode ();
  665.  
  666.     /* FIXME: Missing on slang endwin? */
  667.     reset_prog_mode ();
  668.     flushinp ();
  669.     
  670.     keypad (stdscr, TRUE);
  671.     mc_raw_mode ();
  672.     channels_up ();
  673.     if (use_mouse_p)
  674.     init_mouse ();
  675.     if (alternate_plus_minus && (console_flag || xterm_flag)) {
  676.         fprintf (stderr, "\033="); fflush (stderr);
  677.     }
  678.         
  679. #endif /* have_x */
  680. #ifdef HAVE_TK
  681.     if (iconify_on_exec)
  682.     tk_evalf ("wm deiconify .");
  683. #endif
  684. }
  685.  
  686. /* Save current stat of directories to avoid reloading the panels */
  687. /* when no modifications have taken place */
  688. void save_cwds_stat (void)
  689. {
  690.     if (fast_reload){
  691.     mc_stat (cpanel->cwd, &(cpanel->dir_stat));
  692.     if (get_other_type () == view_listing)
  693.         mc_stat (opanel->cwd, &(opanel->dir_stat));
  694.     }
  695. }
  696.  
  697. #ifdef HAVE_SUBSHELL_SUPPORT
  698. void do_possible_cd (char *new_dir)
  699. {
  700.     if (!do_cd (new_dir))
  701.     message (1, " Warning ",
  702.          " The Commander can't change to the directory that \n"
  703.          " the subshell claims you are in.  Perhaps you have \n"
  704.          " deleted your working directory, or given yourself \n"
  705.          " extra access permissions with the \"su\" command? ");
  706. }
  707.  
  708. void do_update_prompt ()
  709. {
  710.     if (update_prompt){
  711.     printf ("%s", subshell_prompt);
  712.     fflush (stdout);
  713.     update_prompt = 0;
  714.     }
  715. }
  716. #endif
  717.  
  718. void restore_console (void)
  719. {
  720.     handle_console (CONSOLE_RESTORE);
  721. }
  722.  
  723. void exec_shell ()
  724. {
  725.     int old_use_subshell = use_subshell;
  726.  
  727.     do_execute (shell, 0, 1);
  728.     use_subshell = old_use_subshell;
  729. }
  730.  
  731. void do_execute (const char *shell, const char *command, int internal_command)
  732. {
  733. #ifdef HAVE_SUBSHELL_SUPPORT
  734.     char *new_dir = NULL;
  735. #ifdef USE_VFS
  736.     char *old_vfs_dir = 0;
  737.  
  738.     if (!vfs_current_is_local ())
  739.     old_vfs_dir = strdup (vfs_get_current_dir ());
  740. #endif
  741. #endif
  742.  
  743.     save_cwds_stat ();
  744.     pre_exec ();
  745.     if (console_flag)
  746.     restore_console ();
  747.  
  748.     unlink (control_file);
  749.     if (!use_subshell && !internal_command){
  750.     printf ("%s%s%s\n", last_paused ? "\r\n":"", prompt, command);
  751.     last_paused = 0;
  752.     }
  753.  
  754. #ifdef HAVE_SUBSHELL_SUPPORT
  755.     if (use_subshell && !internal_command){
  756.     do_update_prompt ();
  757.  
  758.     /* We don't care if it died, higher level takes care of this */
  759.     invoke_subshell (command, VISIBLY, &new_dir);
  760.     } else
  761. #endif
  762.     my_system (!internal_command, shell, command);
  763.  
  764.     if (!internal_command){
  765.     if (console_flag){
  766.         if (output_lines && keybar_visible)
  767.         putchar('\n');
  768.         handle_console (CONSOLE_SAVE);
  769.     }
  770.  
  771.     if (pause_after_run == pause_always ||
  772.         (pause_after_run == pause_on_dumb_terminals &&
  773.          !xterm_flag && !console_flag)){
  774.         printf ("Press any key to continue...");
  775.         last_paused = 1;
  776.         fflush (stdout);
  777.         mc_raw_mode ();
  778.         xgetch ();
  779.         /* printf ("\r\n");
  780.         fflush (stdout); */
  781.     }
  782.     }
  783.  
  784.     post_exec ();
  785.  
  786. #ifdef HAVE_SUBSHELL_SUPPORT
  787.     if (new_dir){
  788.         do_possible_cd (new_dir);
  789. #    ifdef USE_VFS
  790.         if (old_vfs_dir){
  791.         mc_chdir (old_vfs_dir);
  792.         free (old_vfs_dir);
  793.         }
  794. #    endif
  795.     }
  796. #endif
  797.  
  798.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  799.     
  800. #ifdef WANT_PARSE
  801.     parse_control_file ();
  802. #endif
  803.     unlink (control_file);
  804.     do_refresh ();
  805.     use_dash (TRUE);
  806. }
  807.  
  808. /* Executes a command */
  809. void shell_execute (char *command, int internal)
  810. {
  811. #ifdef HAVE_SUBSHELL_SUPPORT
  812.     if (use_subshell)
  813.     if (subshell_state == INACTIVE)
  814.         do_execute (shell, command, internal);
  815.     else
  816.         message (1, " Error ", " The shell is already running a command ");
  817.     else
  818. #endif
  819.  
  820.     do_execute (shell, command, internal);
  821. }
  822.  
  823. void execute (char *command)
  824. {
  825.     shell_execute (command, 0);
  826. }
  827.  
  828. void change_panel (void)
  829. {
  830.     free_completions (input_w (cmdline));
  831. /*  #ifdef HAVE_X
  832.     send_message (midnight_dlg, (Widget *) cpanel, WIDGET_UNFOCUS, 0);
  833.     send_message (midnight_dlg, (Widget *) opanel, WIDGET_FOCUS, 0);
  834.     #else
  835.     #endif
  836. */
  837.     dlg_one_down (midnight_dlg);
  838. }
  839.  
  840. static int quit_cmd_internal (int quiet)
  841. {
  842.     if (quiet || !confirm_exit){
  843.     quit = 1;
  844.     } else  {
  845.     if (query_dialog (" The Midnight Commander ",
  846.              " Do you really want to quit the Midnight Commander? ",
  847.               0, 2, " Yes ", " No ") == 0)
  848.         quit = 1;
  849.     }
  850.     if (quit){
  851. #ifdef HAVE_SUBSHELL_SUPPORT
  852.     if (!use_subshell)
  853.         midnight_dlg->running = 0;
  854.     else
  855.         if ((quit = exit_subshell ()))
  856. #endif
  857.         midnight_dlg->running = 0;
  858.     }
  859.     return quit;
  860. }
  861.  
  862. int quit_cmd (void)
  863. {
  864.     quit_cmd_internal (0);
  865.     return quit;
  866. }
  867.  
  868. int quiet_quit_cmd (void)
  869. {
  870.     print_last_revert = 1;
  871.     quit_cmd_internal (1);
  872.     return quit;
  873. }
  874.  
  875. /*
  876.  * Touch window and refresh window functions
  877.  */
  878.  
  879. /* This routine untouches the first line on both panels in order */
  880. /* to avoid the refreshing the menu bar */
  881. void untouch_bar (void)
  882. {
  883. #ifndef HAVE_X
  884.     do_refresh ();
  885. #endif
  886. }
  887.  
  888. void repaint_screen (void)
  889. {
  890. #ifndef HAVE_X
  891.     /* Are there pieces of code unpainted, this may be the offending line,
  892.      * uncomment it: */
  893. /*    touchwin (stdscr); */
  894.     do_refresh ();
  895.     refresh ();
  896. #endif
  897. }
  898.  
  899. #if 0
  900. void refresh_screen (void *unused)
  901. {
  902. #ifndef HAVE_X
  903.     touchwin (stdscr);
  904.     refresh ();
  905. #endif
  906. }
  907. #endif
  908.  
  909. /* Wrapper for do_subshell_chdir, check for availability of subshell */
  910. void subshell_chdir (char *directory)
  911. {
  912. #ifdef HAVE_SUBSHELL_SUPPORT
  913.     if (use_subshell){
  914.     if (vfs_current_is_local ())
  915.         do_subshell_chdir (directory, 0, 1);
  916.     }
  917. #endif
  918. }
  919.  
  920. /* Changes the current panel directory */
  921. int do_panel_cd (WPanel *panel, char *new_dir)
  922. {
  923.     char *directory, *olddir;
  924.     char temp [MC_MAXPATHLEN];
  925.  
  926.     olddir = strdup (panel->cwd);
  927.  
  928.     /* Convert *new_path to a suitable pathname, handle ~user */
  929.     
  930.     while (*new_dir == ' ')
  931.     new_dir++;
  932.  
  933.     if (!strcmp (new_dir, "-")){
  934.     strcpy (temp, panel->lwd);
  935.     new_dir = temp;
  936.     }
  937.     directory = *new_dir ? new_dir : home_dir;
  938.  
  939.     if (mc_chdir (directory) == -1){
  940.     strcpy (panel->cwd, olddir);
  941.     free (olddir);
  942.     return 0;
  943.     }
  944.  
  945.     /* Success: save previous directory, shutdown status of previous dir */
  946.     strcpy (panel->lwd, olddir);
  947.     free (olddir);
  948.     free_completions (input_w (cmdline));
  949.     
  950.     mc_get_current_wd (panel->cwd, sizeof (panel->cwd) - 2);
  951.  
  952.     subshell_chdir (directory);
  953.  
  954.     /* Reload current panel */
  955.     clean_dir (&panel->dir, panel->count);
  956.     panel->count = do_load_dir (&panel->dir, panel->sort_type,
  957.                  panel->reverse, panel->case_sensitive, panel->filter);
  958.     panel->top_file = 0;
  959.     panel->selected = 0;
  960.     panel->marked = 0;
  961.     panel->dirs_marked = 0;
  962.     panel->total = 0;
  963.     cd_try_to_select (panel);
  964.     load_hint ();
  965.     panel_update_contents (panel);
  966.     return 1;
  967. }
  968.  
  969. int do_cd (char *new_dir)
  970. {
  971.     return do_panel_cd (cpanel, new_dir);
  972. }
  973.  
  974. #ifdef HAVE_SUBSHELL_SUPPORT
  975. int load_prompt (int fd, void *unused)
  976. {
  977.     if (!read_subshell_prompt (QUIETLY))
  978.     return 0;
  979.     
  980.     if (command_prompt){
  981.     int  prompt_len;
  982.  
  983.     prompt = strip_ctrl_codes (subshell_prompt);
  984.     prompt_len = strlen (prompt);
  985.  
  986.     /* Check for prompts too big */
  987.     if (prompt_len > COLS - 8) {
  988.         prompt [COLS - 8 ] = 0;
  989.         prompt_len = COLS - 8;
  990.     }
  991.     winput_set_origin ((WInput *)cmdline, prompt_len, COLS-prompt_len);
  992.     label_set_text (the_prompt, prompt);
  993.  
  994.     /* since the prompt has changed, and we are called from one of the 
  995.      * get_event channels, the prompt updating does not take place
  996.      * automatically: force a cursor update and a screen refresh
  997.      */
  998.     if (current_dlg == midnight_dlg){
  999.         update_cursor (midnight_dlg);
  1000.         refresh ();
  1001.     }
  1002.     }
  1003.     update_prompt = 1;
  1004.     return 0;
  1005. }
  1006. #endif
  1007.  
  1008. /* The user pressed the enter key */
  1009. int menu_bar_event (Gpm_Event *event, void *x)
  1010. {
  1011.     if (event->type != GPM_DOWN)
  1012.     return MOU_NORMAL;
  1013.  
  1014.     return MOU_ENDLOOP;
  1015. }
  1016.  
  1017. /* Used to emulate Lynx's entering leaving a directory with the arrow keys */
  1018. int maybe_cd (int char_code, int move_up_dir)
  1019. {
  1020.     if (navigate_with_arrows){
  1021.     if (!input_w (cmdline)->buffer [0]){
  1022.         if (!move_up_dir){
  1023.         do_cd ("..");
  1024.         return 1;
  1025.         }
  1026.         if (S_ISDIR (selection (cpanel)->buf.st_mode)
  1027.         || link_isdir (selection (cpanel))){
  1028.         do_cd (selection (cpanel)->fname);
  1029.         return 1;
  1030.         }
  1031.     }
  1032.     }
  1033.     return 0;
  1034. }
  1035.  
  1036. #if 0
  1037. static void tree_leave (WPanel *p)
  1038. {
  1039.     char *dir;
  1040.     int change = 0;
  1041.     
  1042.     dir = p->cwd;
  1043.     if (cpanel != p){
  1044.     change_panel ();
  1045.     change = 1;
  1046.     }
  1047.     if (!do_cd (dir))
  1048.     message (1, " Error ", " Can't chdir to \"%s\" \n %s ",
  1049.          dir, unix_error_string (errno));
  1050.     if (change)
  1051.     change_panel ();
  1052. }
  1053. #endif
  1054.  
  1055. static void info_cmd_no_menu (void)
  1056. {
  1057.     set_display_type (cpanel == left_panel ? 1 : 0, view_info);
  1058. }
  1059.  
  1060. static void quick_cmd_no_menu (void)
  1061. {
  1062.     set_display_type (cpanel == left_panel ? 1 : 0, view_quick);
  1063. }
  1064.  
  1065. static void listing_cmd (void)
  1066. {
  1067.     int   view_type, use_msformat;
  1068.     char  *user, *status;
  1069.     WPanel *p;
  1070.     int   display_type;
  1071.  
  1072.     display_type = get_display_type (MENU_PANEL_IDX);
  1073.     if (display_type == view_listing)
  1074.     p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
  1075.     else
  1076.     p = 0;
  1077.  
  1078.     view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
  1079.  
  1080.     if (view_type == -1)
  1081.     return;
  1082.  
  1083.     if (get_display_type (MENU_PANEL_IDX) != view_listing)
  1084.     set_display_type (MENU_PANEL_IDX, view_listing);
  1085.  
  1086.     p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;    
  1087.     free (p->user_format);
  1088.     p->user_format = user;
  1089.     free (p->mini_status_format);
  1090.     p->mini_status_format = status;
  1091.      
  1092.     p->user_mini_status = use_msformat; 
  1093.     p->list_type = view_type;
  1094.     
  1095.     if (set_panel_format (p, panel_format (p)))
  1096.     set_panel_format (p, DEFAULT_USER_FORMAT);
  1097.     do_refresh ();
  1098. }
  1099.  
  1100. void tree_cmd (void)
  1101. {
  1102.     set_display_type (MENU_PANEL_IDX, view_tree);
  1103. }
  1104.  
  1105. static void info_cmd (void)
  1106. {
  1107.     set_display_type (MENU_PANEL_IDX, view_info);
  1108. }
  1109.  
  1110. void quick_view_cmd (void)
  1111. {
  1112.     set_display_type (MENU_PANEL_IDX, view_quick);
  1113. }
  1114.  
  1115. static void sort_cmd (void)
  1116. {
  1117.     WPanel  *p;
  1118.     sortfn *sort_order;
  1119.  
  1120.     if (!SELECTED_IS_PANEL)
  1121.     return;
  1122.  
  1123.     p = MENU_PANEL;
  1124.     sort_order = sort_box (p->sort_type, &p->reverse, &p->case_sensitive);
  1125.  
  1126.     if (sort_order == 0)
  1127.     return;
  1128.  
  1129.     p->sort_type = sort_order;
  1130.  
  1131.     /* The directory is already sorted, we have to load the unsorted stuff */
  1132.     if (sort_order == (sortfn *) unsorted){
  1133.     char *current_file;
  1134.     
  1135.     current_file = strdup (cpanel->dir.list [cpanel->selected].fname);
  1136.     panel_reload (cpanel);
  1137.     try_to_select (cpanel, current_file);
  1138.     free (current_file);
  1139.     }
  1140.     do_re_sort (p);
  1141. }
  1142.  
  1143. static void tree_box (void)
  1144. {
  1145.     char *sel_dir;
  1146.  
  1147.     sel_dir = tree (selection (cpanel)->fname);
  1148.     if (sel_dir){
  1149.     try_to_select (cpanel, sel_dir);
  1150.     free (sel_dir);
  1151.     }
  1152. }
  1153.  
  1154. #if VERSION_4
  1155. static void listmode_cmd (void)
  1156. {
  1157.     char *newmode;
  1158.     newmode = listmode_edit ("half <type,>name,|,size:8,|,perm:4+");
  1159.     message (0, " Listing format edit ", " New mode is \"%s\" ", newmode);
  1160.     free (newmode);
  1161. }
  1162. #endif
  1163.  
  1164. #ifdef _OS_NT
  1165. /* Hacked from the Antonio Palama's port of MC 1.1 to DOS  */
  1166. void drive_cmd()
  1167. {
  1168.     int d, new_d;
  1169.     char *drive;
  1170.     char buf[5];
  1171.     
  1172.     d = _getdrive();
  1173.     drive = input_dialog(" Enter new drive ", "", "");
  1174.     if (strlen(drive) > 0) {
  1175.     *drive = toupper(*drive);
  1176.     new_d = *drive - 'A' + 1;
  1177.     if (new_d != d)  {
  1178.         sprintf (buf, "%c:", *drive);
  1179.         SetCurrentDirectory(buf);           
  1180.             getcwd (cpanel->cwd, sizeof (cpanel->cwd)-2);
  1181.             if (*drive == toupper(*(cpanel->cwd)))  {
  1182.         clean_dir (&cpanel->dir, cpanel->count);
  1183.         cpanel->count = do_load_dir (&cpanel->dir, cpanel->sort_type,
  1184.                          cpanel->reverse, cpanel->filter);
  1185.         cpanel->top_file = 0;
  1186.         cpanel->selected = 0;
  1187.         cpanel->marked = 0;
  1188.         cpanel->total = 0;
  1189.         show_dir(cpanel);
  1190.         reread_cmd();
  1191.             } else
  1192.         message (1, " Error ", " Can't access drive %c: \n", *drive);
  1193.     }
  1194.     }
  1195.    free(drive);
  1196. }
  1197. #endif
  1198.  
  1199. static menu_entry PanelMenu [] = {
  1200.     { ' ', "Listing mode...",    'L',        listing_cmd },
  1201.     { ' ', "Quick view",        'Q',        quick_view_cmd }, 
  1202.     { ' ', "Info",              'I',        info_cmd },
  1203.     { ' ', "Tree",              'T',        tree_cmd },
  1204.     { ' ', "", ' ', 0 },
  1205.     { ' ', "Sort order...",     'S',        sort_cmd },
  1206.     { ' ', "", ' ', 0 },
  1207.     { ' ', "Filter...",            'F',        filter_cmd },
  1208. #ifdef USE_NETCODE
  1209.     { ' ', "", ' ', 0 },
  1210.     { ' ', "Network link...",   'N',        netlink_cmd },
  1211.     { ' ', "FTP link...",       'P',        ftplink_cmd },
  1212. #endif
  1213.     { ' ', "", ' ', 0 },
  1214. #ifdef _OS_NT
  1215.     { ' ', "Drive...  M-d",         ALT('d'),drive_cmd },
  1216. #endif
  1217.     { ' ', "Rescan    C-r",         XCTRL('R'), reread_cmd }
  1218. };
  1219.  
  1220. static menu_entry RightMenu [] = {
  1221.     { ' ', "Listing mode...",    'L',        listing_cmd },
  1222.     { ' ', "Quick view",        'Q',        quick_view_cmd }, 
  1223.     { ' ', "Info",              'I',        info_cmd },
  1224.     { ' ', "Tree",              'T',        tree_cmd },
  1225.     { ' ', "", ' ', 0 },
  1226.     { ' ', "Sort order...",     'S',        sort_cmd },
  1227.     { ' ', "", ' ', 0 },
  1228.     { ' ', "Filter...",            'F',        filter_cmd },
  1229. #ifdef USE_NETCODE
  1230.     { ' ', "", ' ', 0 },
  1231.     { ' ', "Network link...",   'N',        netlink_cmd },
  1232.     { ' ', "FTP link...",       'P',        ftplink_cmd },
  1233. #endif
  1234.     { ' ', "", ' ', 0 },
  1235. #ifdef _OS_NT
  1236.     { ' ', "Drive...  M-d",         ALT('d'),drive_cmd },
  1237. #endif
  1238.     { ' ', "Rescan    C-r",         XCTRL('R'), reread_cmd }
  1239. };
  1240.  
  1241.  
  1242. static menu_entry FileMenu [] = {
  1243.     { ' ', "User menu          F2",     KEY_F(2), user_menu_cmd },
  1244.     { ' ', "View               F3",     KEY_F(3), view_cmd },
  1245.     { ' ', "Filtered view     M-!",     ALT('!'), filtered_view_cmd },
  1246.     { ' ', "Edit               F4",     KEY_F(4), edit_cmd },
  1247.     { ' ', "Copy               F5",     KEY_F(5), copy_cmd },
  1248.     { ' ', "Link            C-x l",  'L',      link_cmd },
  1249.     { ' ', "SymLink         C-x s",  'S',      symlink_cmd },
  1250.     { ' ', "edit sYmlink  C-x C-s",  'Y',      edit_symlink_cmd },
  1251.     { ' ', "Chmod           C-x c",  'C',      chmod_cmd },
  1252. #ifndef _OS_NT
  1253.     { ' ', "chOwn           C-x o",  'O',      chown_cmd },
  1254.     { ' ', "Advanced chown       ",  'A',      chown_advanced_cmd },
  1255. #endif
  1256.     { ' ', "Rename/Move        F6",     KEY_F(6), ren_cmd },
  1257.     { ' ', "Mkdir              F7",     KEY_F(7), mkdir_cmd },
  1258.     { ' ', "Delete             F8",     KEY_F(8), delete_cmd },
  1259.     { ' ', "Quick cd          M-c",    ALT('c'), quick_cd_cmd },
  1260.     { ' ', "", ' ', 0 },
  1261.     { ' ', "Select group      M-+",    ALT('+'),      select_cmd },
  1262.     { ' ', "Unselect group    M-\\",   ALT('\\'),   unselect_cmd },
  1263.     { ' ', "Reverse selection M-*",  ALT('*'),      reverse_selection_cmd },
  1264.     { ' ', "", ' ', 0 },
  1265.     { ' ', "Quit            F10",    KEY_F(10), (callfn) quit_cmd }
  1266. };
  1267.  
  1268. void external_panelize (void);
  1269. static menu_entry CmdMenu [] = {
  1270.     /* I know, I'm lazy, but the tree widget when it's not running
  1271.      * as a panel still has some problems, I have not yet finished
  1272.      * the WTree widget port, sorry.
  1273.      */
  1274.     { ' ', "Directory tree",            'D',          tree_box },
  1275.     { ' ', "Find file            M-?",  ALT('?'),     find_cmd },
  1276. #ifndef HAVE_XVIEW    
  1277.     { ' ', "Swap panels          C-u",  XCTRL('u'),   swap_cmd },
  1278.     { ' ', "Switch panels on/off C-o",  XCTRL('o'),   view_other_cmd },
  1279. #endif    
  1280.     { ' ', "Compare directories",    'C',          compare_dirs_cmd },
  1281.     { ' ', "eXternal panelize    C-x !",'X',          external_panelize },
  1282. #ifdef HAVE_DUSUM
  1283.     { ' ', "show directory sIzes",      'I',          dirsizes_cmd },
  1284. #endif
  1285.     { ' ', "", ' ', 0 },
  1286.     { ' ', "command History",           'H',          history_cmd },
  1287.     { ' ', "Directory hotlist    C-\\",  XCTRL('\\'), quick_chdir_cmd },
  1288. #ifdef USE_VFS
  1289.     { ' ', "Active VFS list      C-x a", 'A',         reselect_vfs },
  1290. #endif
  1291.     { ' ', "", ' ', 0 },
  1292. #ifdef USE_EXT2FSLIB
  1293.     { ' ', "Undelete files (ext2fs only)",'U',        undelete_cmd },
  1294. #endif
  1295. #ifdef VERSION_4
  1296.     { ' ', "Listing format edit",    'L',          listmode_cmd},
  1297. #endif
  1298.     { ' ', "Extension file edit",    'E',          ext_cmd },
  1299.     { ' ', "Menu file edit",        'M',          menu_edit_cmd }
  1300. };
  1301.  
  1302. /* Must keep in sync with the constants in menu_cmd */
  1303. static menu_entry OptMenu [] = {
  1304.     { ' ', "Configuration...",    'C', configure_box },
  1305.     { ' ', "Layout...",           'L', layout_cmd },
  1306.     { ' ', "cOnfirmation...",     'O', confirm_box },
  1307.     { ' ', "Display bits...",     'D', display_bits_box },
  1308. #ifndef HAVE_X
  1309.     { ' ', "learn Keys...",       'K', learn_keys },
  1310. #endif
  1311. #ifdef USE_VFS    
  1312.     { ' ', "Virtual FS...",      'V', configure_vfs },
  1313. #endif
  1314.     { ' ', "", ' ', 0 }, 
  1315.     { ' ', "Save setup",          'S', save_setup_cmd }
  1316. };
  1317.  
  1318. #define menu_entries(x) sizeof(x)/sizeof(menu_entry)
  1319.  
  1320. Menu MenuBar [5];
  1321. #ifndef HAVE_X
  1322. static Menu MenuBarEmpty [5];
  1323. #endif
  1324.  
  1325. static void init_menu (void)
  1326. {
  1327.     int i;
  1328.     
  1329.     MenuBar [0] = create_menu (" Left ", PanelMenu, menu_entries (PanelMenu));
  1330.     MenuBar [1] = create_menu (" File ", FileMenu, menu_entries (FileMenu));
  1331.     MenuBar [2] = create_menu (" Command ", CmdMenu, menu_entries (CmdMenu));
  1332.     MenuBar [3] = create_menu (" Options ", OptMenu, menu_entries (OptMenu));
  1333. #ifndef HAVE_XVIEW
  1334.     MenuBar [4] = create_menu (" Right ", RightMenu, menu_entries (PanelMenu));
  1335.  
  1336. #ifndef HAVE_X
  1337.     for (i = 0; i < 5; i++)
  1338.     MenuBarEmpty [i] = create_menu (MenuBar [i]->name, 0, 0);
  1339. #endif /* ! HAVE_X */
  1340. #endif /* ! HAVE_XVIEW */
  1341. }
  1342.  
  1343. static void done_menu (void)
  1344. {
  1345.     int i;
  1346.  
  1347. #ifndef HAVE_XVIEW
  1348.     for (i = 0; i < 5; i++){
  1349.     destroy_menu (MenuBar [i]);
  1350. #ifndef HAVE_X
  1351.     destroy_menu (MenuBarEmpty [i]);
  1352. #endif
  1353. #else
  1354.     for (i = 0; i < 4; i++){
  1355.     destroy_menu (MenuBar [i]);
  1356. #endif
  1357.     }
  1358. }
  1359.  
  1360. /* All the drop_menu mess is so that the user could select from the
  1361.    capital letters on the MenuBar.  Suggested by Torben */
  1362.  
  1363. enum {
  1364.     menu_select_current,
  1365.     menu_select_last,
  1366.     menu_select_pos
  1367. };
  1368.  
  1369. static void menu_last_selected_cmd (void)
  1370. {
  1371.     the_menubar->active = 1;
  1372.     the_menubar->dropped = drop_menus;
  1373.     the_menubar->previous_selection = dlg_item_number (midnight_dlg);
  1374.     dlg_select_widget (midnight_dlg, the_menubar);
  1375. }
  1376.  
  1377. static void menu_cmd (void)
  1378. {
  1379.     if (the_menubar->active)
  1380.     return;
  1381.     
  1382.     if (get_current_index () == 0)
  1383.     the_menubar->selected = 0;
  1384.     else
  1385.     the_menubar->selected = 4;
  1386.     menu_last_selected_cmd ();
  1387. }
  1388.  
  1389. /* Flag toggling functions */
  1390. void toggle_confirm_delete (void)
  1391. {
  1392.     confirm_delete = !confirm_delete;
  1393. }
  1394.  
  1395. void toggle_fast_reload (void)
  1396. {
  1397.     fast_reload = !fast_reload;
  1398.     if (fast_reload_w == 0 && fast_reload){
  1399.     message (0, " Information ",
  1400.          " Using the fast reload option may not reflect the exact \n"
  1401.          " directory contents. In this cases you'll need to do a  \n"
  1402.          " manual reload of the directory. See the man page for   \n"
  1403.          " the details.                                           ");
  1404.     fast_reload_w = 1;
  1405.     }
  1406. }
  1407.  
  1408. void toggle_mix_all_files (void)
  1409. {
  1410.     mix_all_files = !mix_all_files;
  1411.     update_panels (UP_RELOAD, UP_KEEPSEL, UP_KEEPSEL);
  1412. }
  1413.  
  1414. void toggle_show_backup (void)
  1415. {
  1416.     show_backups = !show_backups;
  1417.     update_panels (UP_RELOAD, UP_KEEPSEL, UP_KEEPSEL);
  1418. }
  1419.  
  1420. void toggle_show_hidden (void)
  1421. {
  1422.     show_dot_files = !show_dot_files;
  1423.     update_panels (UP_RELOAD, UP_KEEPSEL, UP_KEEPSEL);
  1424. }
  1425.  
  1426. void toggle_show_mini_status (void)
  1427. {
  1428.     show_mini_info = !show_mini_info;
  1429.     paint_panel (cpanel);
  1430.     if (get_other_type () == view_listing)
  1431.     paint_panel (opanel);
  1432. }
  1433.  
  1434. void toggle_align_extensions (void)
  1435. {
  1436.     align_extensions = !align_extensions;
  1437. }
  1438.  
  1439. static void create_panels (void)
  1440. {
  1441.     int current_index;
  1442.     int other_index;
  1443.     int current_mode;
  1444.     int other_mode;
  1445.     char original_dir [1024];
  1446.  
  1447.     original_dir [0] = 0;
  1448.     
  1449.     if (boot_current_is_left){
  1450.     current_index = 0;
  1451.     other_index = 1;
  1452.     current_mode = startup_left_mode;
  1453.     other_mode = startup_right_mode;
  1454.     } else {
  1455.     current_index = 1;
  1456.     other_index = 0;
  1457.     current_mode = startup_right_mode;
  1458.     other_mode = startup_left_mode;
  1459.     }
  1460.     /* Creates the left panel */
  1461.     if (this_dir){
  1462.     if (other_dir){
  1463.         /* Ok, user has specified two dirs, save the original one,
  1464.          * since we may not be able to chdir to the proper
  1465.          * second directory later
  1466.          */
  1467.         mc_get_current_wd (original_dir, sizeof (original_dir)-2);
  1468.     }
  1469.     mc_chdir (this_dir);
  1470.     }
  1471.     set_display_type (current_index, current_mode);
  1472.  
  1473.     /* The other panel */
  1474.     if (other_dir){
  1475.     if (original_dir [0])
  1476.         mc_chdir (original_dir);
  1477.     mc_chdir (other_dir);
  1478.     }
  1479.     set_display_type (other_index, other_mode);
  1480.  
  1481.     if (startup_left_mode == view_listing){
  1482.     cpanel = left_panel;
  1483.     } else {
  1484.     if (right_panel)
  1485.         cpanel = right_panel;
  1486.     else
  1487.         cpanel = left_panel;
  1488.     }
  1489.  
  1490.     /* Create the nice widgets */
  1491.     cmdline     = command_new (0, 0, 0);
  1492.     the_prompt  = label_new (0, 0, prompt);
  1493.     the_prompt->transparent = 1;
  1494.     the_bar     = buttonbar_new (keybar_visible);
  1495.     the_hint    = label_new (0, 0, 0);
  1496.     the_hint->transparent = 1;
  1497.     the_hint->auto_adjust_cols = 0;
  1498.     the_hint->widget.cols = COLS;
  1499.                  
  1500. #ifndef HAVE_XVIEW
  1501.     the_menubar = menubar_new (0, 0, COLS, MenuBar, 5);
  1502. #else
  1503.     the_menubar = menubar_new (0, 0, COLS, MenuBar + 1, 3);
  1504.     the_bar2    = buttonbar_new (keybar_visible);
  1505. #endif
  1506. }
  1507.  
  1508. static void copy_current_pathname (void)
  1509. {
  1510.     if (!command_prompt)
  1511.     return;
  1512.  
  1513.     stuff (input_w (cmdline), cpanel->cwd, 0);
  1514.     if (cpanel->cwd [strlen (cpanel->cwd) - 1] != PATH_SEP)
  1515.         stuff (input_w (cmdline), PATH_SEP_STR, 0);
  1516. }
  1517.  
  1518. static void copy_other_pathname (void)
  1519. {
  1520.     if (get_other_type () != view_listing)
  1521.     return;
  1522.  
  1523.     if (!command_prompt)
  1524.     return;
  1525.  
  1526.     stuff (input_w (cmdline), opanel->cwd, 0);
  1527.     if (cpanel->cwd [strlen (opanel->cwd) - 1] != PATH_SEP)
  1528.         stuff (input_w (cmdline), PATH_SEP_STR, 0);
  1529. }
  1530.  
  1531. static void copy_readlink (WPanel *panel)
  1532. {
  1533.     if (!command_prompt)
  1534.     return;
  1535.     if (S_ISLNK (selection (panel)->buf.st_mode)) {
  1536.     char buffer [MC_MAXPATHLEN], *p = (panel->cwd [strlen (panel->cwd) - 1] != PATH_SEP) ? 
  1537.       copy_strings (panel->cwd, PATH_SEP_STR, selection (panel)->fname, NULL) :
  1538.       copy_strings (panel->cwd, selection (panel)->fname, NULL);
  1539.     int i;
  1540.     
  1541.     i = readlink (p, buffer, MC_MAXPATHLEN);
  1542.     free (p);
  1543.     if (i > 0) {
  1544.         buffer [i] = 0;
  1545.         stuff (input_w (cmdline), buffer, 0);
  1546.     }
  1547.     }
  1548. }
  1549.  
  1550. static void copy_current_readlink (void)
  1551. {
  1552.     copy_readlink (cpanel);
  1553. }
  1554.  
  1555. static void copy_other_readlink (void)
  1556. {
  1557.     if (get_other_type () != view_listing)
  1558.     return;
  1559.     copy_readlink (opanel);
  1560. }
  1561.  
  1562. /* Inserts the selected file name into the input line */
  1563. /* Exported so that the command modules uses it */
  1564. void copy_prog_name (void)
  1565. {
  1566.     if (!command_prompt)
  1567.     return;
  1568.  
  1569.     if (get_current_type () == view_tree){
  1570.     WTree *tree = (WTree *) get_panel_widget (get_current_index ());
  1571.  
  1572.     stuff (input_w (cmdline), tree->selected_ptr->name, 1);
  1573.     } else
  1574.     stuff (input_w (cmdline), selection (cpanel)->fname, 1);
  1575. }
  1576.  
  1577. static void copy_tagged (WPanel *panel)
  1578. {
  1579.     int i;
  1580.  
  1581.     if (!command_prompt)
  1582.     return;
  1583.     input_disable_update (input_w (cmdline));
  1584.     if (panel->marked){
  1585.     for (i = 0; i < panel->count; i++)
  1586.         if (panel->dir.list [i].f.marked)
  1587.         stuff (input_w (cmdline), panel->dir.list [i].fname, 1);
  1588.     } else 
  1589.     stuff (input_w (cmdline), panel->dir.list [panel->selected].fname, 1);
  1590.     input_enable_update (input_w (cmdline));
  1591. }
  1592.     
  1593. static void copy_current_tagged (void)
  1594. {
  1595.     copy_tagged (cpanel);
  1596. }
  1597.  
  1598. static void copy_other_tagged (void)
  1599. {
  1600.     if (get_other_type () != view_listing)
  1601.     return;
  1602.     copy_tagged (opanel);
  1603. }
  1604.  
  1605. static void do_suspend_cmd (void)
  1606. {
  1607.     pre_exec ();
  1608.  
  1609.     if (console_flag && !use_subshell)
  1610.     restore_console ();
  1611.  
  1612. #ifndef _OS_NT
  1613.     {
  1614.     struct sigaction sigtstp_action;
  1615.     
  1616.     /* Make sure that the SIGTSTP below will suspend us directly,
  1617.        without calling ncurses' SIGTSTP handler; we *don't* want
  1618.        ncurses to redraw the screen immediately after the SIGCONT */
  1619.     sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
  1620.     
  1621.     kill (getpid (), SIGTSTP);
  1622.  
  1623.     /* Restore previous SIGTSTP action */
  1624.     sigaction (SIGTSTP, &sigtstp_action, NULL);
  1625.     }
  1626. #endif
  1627.     
  1628.     if (console_flag && !use_subshell)
  1629.     handle_console (CONSOLE_SAVE);
  1630.     
  1631.     post_exec ();
  1632. }
  1633.  
  1634. void suspend_cmd (void)
  1635. {
  1636.     save_cwds_stat ();
  1637.     do_suspend_cmd ();
  1638.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  1639.     do_refresh ();
  1640. }
  1641.  
  1642. void init_labels (Widget *paneletc)
  1643. {
  1644.     define_label (midnight_dlg, paneletc, 1, "Help", help_cmd);
  1645.     define_label (midnight_dlg, paneletc, 2, "Menu", user_menu_cmd);
  1646.     define_label (midnight_dlg, paneletc, 9, "PullDn", menu_cmd);
  1647.     define_label (midnight_dlg, paneletc, 10, "Quit", (voidfn) quit_cmd);
  1648. }
  1649.  
  1650. static void save_setup_cmd (void)
  1651. {
  1652.     save_setup ();
  1653.     sync_profiles ();
  1654.     message (0, " Setup ", " Setup saved to ~/.mc.ini ");
  1655. }
  1656.  
  1657. #ifndef HAVE_XVIEW
  1658. static key_map ctl_x_map [] = {
  1659.     { XCTRL('c'),   (callfn) quit_cmd },
  1660. #ifdef USE_VFS
  1661.     { 'a',          reselect_vfs },
  1662. #endif
  1663.     { 'd',          compare_dirs_cmd },
  1664.     { 'p',          copy_current_pathname },
  1665.     { XCTRL('p'),   copy_other_pathname },
  1666.     { 't',          copy_current_tagged },
  1667.     { XCTRL('t'),   copy_other_tagged },
  1668.     { 'c',          chmod_cmd },
  1669. #ifndef _OS_NT
  1670.     { 'o',          chown_cmd },
  1671. #endif
  1672.     { 'l',          link_cmd },
  1673.     { XCTRL('l'),   other_symlink_cmd },
  1674.     { 's',          symlink_cmd },
  1675.     { XCTRL('s'),   edit_symlink_cmd },
  1676.     { 'r',          copy_current_readlink },
  1677.     { XCTRL('r'),   copy_other_readlink },
  1678.     { 'i',          info_cmd_no_menu },
  1679.     { 'q',          quick_cmd_no_menu },
  1680.     { 'h',          add2hotlist_cmd },
  1681.     { '!',          external_panelize },
  1682. #ifdef HAVE_SETSOCKOPT
  1683.     { '%',          source_routing },
  1684. #endif
  1685.     { 0,  0 }
  1686. };
  1687.  
  1688. static void ctl_x_cmd (int ignore)
  1689. {
  1690.     int i;
  1691.     int key = mi_getch ();
  1692.  
  1693.     for (i = 0; i < ctl_x_map [i].key_code; i++){
  1694.     if (key == ctl_x_map [i].key_code){
  1695.         (*ctl_x_map [i].fn)(key);
  1696.         break;
  1697.     }
  1698.     }
  1699. }
  1700.  
  1701. static void nothing ()
  1702. {
  1703. }
  1704.  
  1705. static key_map default_map [] = {
  1706.     { KEY_F(19),  menu_last_selected_cmd },
  1707.     
  1708.     { KEY_F(13),  (key_callback) view_simple_cmd },
  1709.     { KEY_F(20),  (key_callback) quiet_quit_cmd },
  1710.  
  1711.     /* Copy useful information to the command line */
  1712.     { ALT('\n'),  copy_prog_name },
  1713.     { ALT('\r'),  copy_prog_name },
  1714.     { ALT('a'),   copy_current_pathname },
  1715.     { ALT('A'),   copy_other_pathname },
  1716.     
  1717.     { ALT('+'),      select_cmd },
  1718.     { ALT('\\'),  unselect_cmd },
  1719.     { ALT('-'),      unselect_cmd },
  1720.     { ALT('*'),      reverse_selection_cmd },
  1721.     
  1722.     { ALT('c'),      quick_cd_cmd },
  1723.  
  1724.     /* To access the directory hotlist */
  1725.     { XCTRL('\\'), quick_chdir_cmd },
  1726.  
  1727.     /* The filtered view command */
  1728.     { ALT('!'),   filtered_view_cmd_cpanel },
  1729.     
  1730.     /* Find file */
  1731.     { ALT('?'),      find_cmd },
  1732.     
  1733.     /* Suspend */
  1734.     { XCTRL('z'), suspend_cmd },
  1735.  
  1736.     /* Panel refresh */
  1737.     { XCTRL('r'), reread_cmd },
  1738.  
  1739. #ifndef HAVE_XVIEW
  1740.     /* Swap panels */
  1741.     { XCTRL('u'), swap_cmd },
  1742.  
  1743.     /* View output */
  1744.     { XCTRL('o'), view_other_cmd },
  1745. #endif
  1746.     
  1747.     /* Control-X keybindings */
  1748.     { XCTRL('x'), ctl_x_cmd },
  1749.  
  1750.     /* Trap dlg's exit commands */
  1751.     { ESC_CHAR,   nothing },
  1752.     { XCTRL('c'), nothing },
  1753.     { XCTRL('g'), nothing },
  1754.     { 0, 0 },
  1755. };
  1756. #endif
  1757.  
  1758. static void setup_sigwinch ()
  1759. {
  1760. #ifndef _OS_NT
  1761.     struct sigaction act, oact;
  1762.     
  1763. #   ifdef HAVE_SLANG
  1764. #       ifdef SIGWINCH
  1765.             act.sa_handler = flag_winch;
  1766.             sigemptyset (&act.sa_mask);
  1767. #           ifdef SA_RESTART
  1768.                 act.sa_flags = SA_RESTART;
  1769. #           endif
  1770.             sigaction (SIGWINCH, &act, &oact);
  1771. #       endif
  1772. #   endif
  1773. #endif
  1774. }
  1775.  
  1776. /* Midnight Commander and file viewer setup */
  1777. static void setup_pre ()
  1778. {
  1779.     /* Call all the inits */
  1780. #   ifndef HAVE_SLANG
  1781.     meta (stdscr, eight_bit_clean);
  1782. #else
  1783.     SLsmg_Display_Eight_Bit = full_eight_bits ? 128 : 160;
  1784. #   endif
  1785. }
  1786.  
  1787. static void setup_post ()
  1788. {
  1789.     setup_sigwinch ();
  1790.     
  1791.     init_uid_gid_cache ();
  1792.  
  1793. #ifndef HAVE_X
  1794.     if (baudrate () < 9600 || slow_terminal){
  1795.     verbose = 0;
  1796.     }
  1797.     if (use_mouse_p)
  1798.     init_mouse ();
  1799. #endif
  1800.  
  1801.     midnight_colors [0] = 0;
  1802.     midnight_colors [1] = REVERSE_COLOR;     /* FOCUSC */
  1803.     midnight_colors [2] = INPUT_COLOR;       /* HOT_NORMALC */
  1804.     midnight_colors [3] = NORMAL_COLOR;         /* HOT_FOCUSC */
  1805. }
  1806.  
  1807. static void setup_mc ()
  1808. {
  1809.     setup_pre ();
  1810.     init_menu ();
  1811.     create_panels ();
  1812.     setup_panels ();
  1813.     
  1814. #ifdef HAVE_SUBSHELL_SUPPORT
  1815.     if (use_subshell)
  1816.     add_select_channel (subshell_pty, load_prompt, 0);
  1817. #endif
  1818.     
  1819.     setup_post ();
  1820. }
  1821.  
  1822. static void setup_mc_viewer ()
  1823. {
  1824.     setup_pre ();
  1825.     setup_post ();
  1826.  
  1827.     /* Create a fake current_panel, this is needed because the
  1828.      * expand_format routine will use current panel.
  1829.      */
  1830.     cpanel = xmalloc (sizeof (WPanel), "fake_panel");
  1831.     strcpy (cpanel->cwd, ".");
  1832.     cpanel->dir.list = (file_entry *) xmalloc (sizeof (file_entry), "fake_p");
  1833.     cpanel->count = 1;
  1834.     cpanel->dir.list [0].fname = view_one_file;
  1835. }
  1836.  
  1837. static void done_screen ()
  1838. {
  1839. /* #ifndef HAVE_X */
  1840.     if (quit != SUBSHELL_EXIT)
  1841.     clr_scr ();
  1842.     reset_shell_mode ();
  1843. #ifndef HAVE_X
  1844.     mc_noraw_mode ();
  1845.     if (use_mouse_p)
  1846.     shut_mouse ();
  1847. #endif
  1848.     keypad (stdscr, FALSE);
  1849. }
  1850.  
  1851. static void done_mc ()
  1852. {
  1853.     done_menu ();
  1854.     
  1855.     /* Setup shutdown
  1856.      *
  1857.      * We sync the profiles since the hotlist may have changed, while
  1858.      * we only change the setup data if we have the auto save feature set
  1859.      */
  1860.     if (auto_save_setup)
  1861.     save_setup ();
  1862.     done_screen ();
  1863.     vfs_add_current_stamps ();
  1864.     if (xterm_flag && xterm_hintbar)
  1865.         set_hintbar("Thank you for using GNU Midnight Commander");
  1866. }
  1867.  
  1868. /* This should be called after destroy_dlg since panel widgets
  1869.  *  save their state on the profiles
  1870.  */
  1871. static void done_mc_profile ()
  1872. {
  1873.     if (!auto_save_setup)
  1874.     profile_forget_profile (profile_name);
  1875.     sync_profiles ();
  1876.     done_setup ();
  1877.     free_profiles ();
  1878. }
  1879.  
  1880. /* This routine only handles cpanel, and opanel, it is easy to
  1881.  * change to use npanels, just loop over the number of panels
  1882.  * and use get_panel_widget (i) and make the test done below
  1883.  */
  1884. void make_panels_dirty ()
  1885. {
  1886.     if (cpanel->dirty)
  1887.     panel_update_contents (cpanel);
  1888.     
  1889.     if ((get_other_type () == view_listing) && opanel->dirty)
  1890.     panel_update_contents (opanel);
  1891. }
  1892.  
  1893. int midnight_callback (struct Dlg_head *h, int id, int msg)
  1894. {
  1895.     int i;
  1896.     
  1897.     switch (msg){
  1898. #ifndef HAVE_XVIEW
  1899.  
  1900.     /* Speed up routine: now, we just set the  */
  1901.     case DLG_PRE_EVENT:
  1902.     make_panels_dirty ();
  1903.     return MSG_HANDLED;
  1904.     
  1905.     case DLG_KEY:
  1906.     if (id == KEY_F(10) && !the_menubar->active){
  1907.         quit_cmd ();
  1908.         return MSG_HANDLED;
  1909.     }
  1910.  
  1911.     if (id == '\t')
  1912.         free_completions (input_w (cmdline));
  1913.  
  1914.     /* On Linux, we can tell the difference */
  1915.     if (id == '\n' && ctrl_pressed ()){
  1916.         copy_prog_name ();
  1917.         return MSG_HANDLED;
  1918.     }
  1919.  
  1920.     if (id == '\n' && input_w (cmdline)->buffer [0]){
  1921.         send_message_to (h, (Widget *) cmdline, WIDGET_KEY, id);
  1922.         return MSG_HANDLED;
  1923.     }
  1924.  
  1925.     if (!alternate_plus_minus || !(console_flag || xterm_flag)) {
  1926.         if(!only_leading_plus_minus) {
  1927.         /* Special treatement, since the input line will eat them */
  1928.         if (id == '+' && !quote && !cpanel->searching){
  1929.             select_cmd ();
  1930.             return MSG_HANDLED;
  1931.         }
  1932.         
  1933.         if (id == '\\' && !quote && !cpanel->searching){
  1934.             unselect_cmd ();
  1935.             return MSG_HANDLED;
  1936.         }
  1937.         } else if (command_prompt && !strlen (input_w (cmdline)->buffer)
  1938.                && !cpanel->searching) {
  1939.         /* Special treatement '+', '-', '\', '*' only when this is 
  1940.          * first char on input line
  1941.          */
  1942.         
  1943.         if (id == '+' && !quote && !cpanel->searching){
  1944.             select_cmd ();
  1945.             return MSG_HANDLED;
  1946.         }
  1947.         
  1948.         if ((id == '\\' || id == '-') && !quote && !cpanel->searching){
  1949.             unselect_cmd ();
  1950.             return MSG_HANDLED;
  1951.         }
  1952.         
  1953.         if (id == '*' && !quote && !cpanel->searching){
  1954.             reverse_selection_cmd ();
  1955.             return MSG_HANDLED;
  1956.         }
  1957.         }   
  1958.     } 
  1959.     break;
  1960.  
  1961.     case DLG_HOTKEY_HANDLED:
  1962.     if (get_current_type () == view_listing)
  1963.         cpanel->searching = 0;
  1964.     break;
  1965.     
  1966.     case DLG_UNHANDLED_KEY:
  1967.     if (command_prompt){
  1968.         int v;
  1969.         
  1970.         v = send_message_to (h, (Widget *) cmdline, WIDGET_KEY, id);
  1971.         if (v)
  1972.         return v;
  1973.     }
  1974.     for (i = 0; default_map [i].key_code; i++){
  1975.         if (id == default_map [i].key_code){
  1976.         (*default_map [i].fn)(id);
  1977.         break;
  1978.         }
  1979.     }
  1980.     if (default_map [i].key_code)
  1981.         return MSG_HANDLED;
  1982.     else
  1983.         return MSG_NOT_HANDLED;
  1984. #endif
  1985. #ifndef HAVE_X
  1986.     /* We handle the special case of the output lines */
  1987.     case DLG_DRAW:
  1988.     attrset (SELECTED_COLOR);
  1989.     if (console_flag && output_lines)
  1990.         show_console_contents (output_start_y,
  1991.                    LINES-output_lines-keybar_visible-1,
  1992.                    LINES-keybar_visible-1);
  1993.     break;
  1994. #endif
  1995.     
  1996.     }
  1997.     return default_dlg_callback (h, id, msg);
  1998. }
  1999.  
  2000. #ifdef HAVE_X
  2001. /* This should be rewritten in order to support as many panel containers as
  2002.    the user wants */
  2003.  
  2004. widget_data containers [2];
  2005. int containers_no = 2;
  2006.  
  2007. void xtoolkit_panel_setup ()
  2008. {
  2009.     containers [0] = x_create_panel_container (0);
  2010.     containers [1] = x_create_panel_container (1);
  2011.     input_w (cmdline)->widget.wcontainer = containers [0];
  2012.     input_w (cmdline)->widget.area = AREA_BOTTOM;
  2013.     the_prompt->widget.wcontainer = containers [0];
  2014.     the_prompt->widget.area = AREA_BOTTOM;
  2015.     the_bar->widget.wcontainer = containers [0];
  2016.     the_bar->widget.area = AREA_TOP;
  2017. #ifdef HAVE_XVIEW
  2018.     the_bar2->widget.wcontainer = containers [1];
  2019.     the_bar2->widget.area = AREA_TOP;
  2020. #endif
  2021.     get_panel_widget (0)->wcontainer = containers [0];
  2022.     get_panel_widget (0)->area = AREA_RIGHT;
  2023.     get_panel_widget (1)->wcontainer = containers [1];
  2024.     get_panel_widget (1)->area = AREA_RIGHT;
  2025.     the_menubar->widget.wcontainer = (widget_data) NULL;
  2026. }
  2027. #else
  2028. #    define xtoolkit_panel_setup()
  2029. #endif
  2030.  
  2031. void load_hint ()
  2032. {
  2033.     char *hint;
  2034.  
  2035.     if (!the_hint->widget.parent)
  2036.     return;
  2037.     
  2038.     if (!message_visible && (!xterm_flag || !xterm_hintbar)){
  2039.         label_set_text (the_hint, 0);
  2040.     return;
  2041.     }
  2042.  
  2043.     if ((hint = get_random_hint ())){
  2044.     if (*hint)
  2045.         set_hintbar (hint);
  2046.     free (hint);
  2047.     } else {
  2048.     set_hintbar ("The Midnight Commander " VERSION
  2049.             " (C) 1995 the Free Software Foundation");
  2050.     }
  2051. }
  2052.  
  2053. static void do_nc (void)
  2054. {
  2055.     int first, second;
  2056.  
  2057.     midnight_dlg = create_dlg (0, 0, LINES, COLS,
  2058.         midnight_colors, midnight_callback, "[main]", "midnight", 0);
  2059.     midnight_dlg->has_menubar = 1;
  2060.     
  2061.     if (view_one_file){
  2062.     /* Invoke the internal view routine with:
  2063.      * the default processing and forcing the internal viewer
  2064.      */
  2065.     setup_mc_viewer ();
  2066.     view_file (view_one_file, 0, 1);
  2067.     midnight_shutdown = 1;
  2068.     done_screen ();
  2069.     return;
  2070.     }
  2071.     setup_mc ();
  2072.  
  2073.     xtoolkit_panel_setup ();
  2074.     tk_new_frame (midnight_dlg, "p.");
  2075. #ifndef HAVE_X
  2076.     add_widget (midnight_dlg, the_hint);
  2077.     load_hint ();
  2078. #endif
  2079.     add_widgetl (midnight_dlg, cmdline, XV_WLAY_RIGHTOF);
  2080.     add_widgetl (midnight_dlg, the_prompt, XV_WLAY_DONTCARE);
  2081.     tk_end_frame ();
  2082.     add_widget (midnight_dlg, the_bar);
  2083. #ifdef HAVE_XVIEW
  2084.     add_widget (midnight_dlg, the_bar2);
  2085. #endif
  2086.     if (boot_current_is_left){
  2087.     first = 1;
  2088.     second = 0;
  2089.     } else {
  2090.     first = 0;
  2091.     second = 1;
  2092.     }
  2093.     add_widget (midnight_dlg, get_panel_widget (first));
  2094.     add_widget (midnight_dlg, get_panel_widget (second));
  2095.     add_widget (midnight_dlg, the_menubar);
  2096.     
  2097.     init_labels (get_panel_widget (0));
  2098.     init_labels (get_panel_widget (1));
  2099.  
  2100.     /* Run the Midnight Commander if no file was specified in the command line */
  2101.     run_dlg (midnight_dlg);
  2102.     midnight_shutdown = 1;
  2103.     
  2104.     /* destroy_dlg destroys even cpanel->cwd, so we have to save a copy :) */
  2105.     if (print_last_wd && !view_one_file){
  2106.     if (vfs_current_is_local ())
  2107.         last_wd_string = strdup (cpanel->cwd);
  2108.     else
  2109.         last_wd_string = strdup (".");
  2110.     }
  2111.     
  2112.     done_mc  ();
  2113.     
  2114.     destroy_dlg (midnight_dlg);
  2115.     done_mc_profile ();
  2116. }
  2117.  
  2118. #if OLD
  2119. static int do_nc (void)
  2120. {
  2121.     int key;
  2122.     int i;
  2123.  
  2124.     if (COLS < 70 || LINES < 22){
  2125.     endwin ();
  2126.     fprintf (stderr, "Screen too small: you need at least 70x22\n");
  2127.     return 0;
  2128.     }
  2129.  
  2130.     init_panels ();
  2131.  
  2132.  
  2133.     /* FIXME: need to run the automenus on the new commander version */
  2134.     if (auto_menu)
  2135.     user_menu_cmd ();
  2136.  
  2137.     
  2138.     /* Main program loop */
  2139.     for (quit = 0; !quit;){
  2140.     remove_dash ();
  2141.     /* we need to change the layout here, since it can't be done   */
  2142.     /* on an inner loop of the program because of the setup frames */
  2143.     if (layout_do_change){
  2144.         layout_change ();
  2145.         refresh_screen (0);
  2146.     }
  2147. #ifdef HAVE_SLANG
  2148.     if (winch_flag)
  2149.         change_screen_size ();
  2150. #endif
  2151.     
  2152.     if (was_searching != searching){
  2153.         display_mini_info (cpanel);
  2154.         refresh ();
  2155.     }
  2156.  
  2157.     /* This is needed for ncurses 1.8.7, ugh :-( */
  2158.     /* Also SysV curses benefits from this */
  2159.     if (command_prompt){
  2160.         leaveok (cmdline_win);
  2161.         wrefresh (cmdline_win);
  2162.     }
  2163.     
  2164.     key = mi_getch ();
  2165.  
  2166.     was_searching = searching;
  2167.     if (quote){
  2168.         default_key (key);
  2169.         quote = 0;
  2170.         continue;
  2171.     }
  2172.     /* This function should set the searching variable to 0 before */
  2173.     /* invoking the appropiate routine */
  2174.     if (check_fkeys (key)){
  2175.         searching = 0;
  2176.         continue;
  2177.     }
  2178.     else {
  2179.     /* Shutdown the program */
  2180.     destroy_input (cmdline, IN_NORMAL);
  2181.     done_mc ();
  2182.     
  2183.     pop_refresh ();
  2184.     return 1;
  2185. }
  2186. #endif /* EVENT mc */
  2187.  
  2188. #ifndef VERSION
  2189. #    define VERSION "undefined"
  2190. #endif
  2191.  
  2192. int stdout_fd = 0;
  2193.     
  2194. static void version (void)
  2195. {
  2196. #ifdef HAVE_X
  2197.     char *version;
  2198.     
  2199. #ifdef HAVE_XVIEW
  2200.     version = "XView";
  2201. #else
  2202.     version = "Tk";
  2203. #endif
  2204.     
  2205.     fprintf (stderr, "%s Midnight Commander %s\n%s", version, VERSION,
  2206. #else /* HAVE_X */
  2207.     fprintf (stderr,
  2208.         "Midnight Commander %s, with mouse support on xterm%s,\n%s%s.\n",
  2209.         VERSION, status_mouse_support ? " and the Linux console" : "",
  2210.         status_using_ncurses ? "using the ncurses library"
  2211. #ifdef HAVE_SLANG
  2212.          : "using the S-Lang library "
  2213. #ifdef SLANG_TERMINFO
  2214.          "with terminfo database",
  2215. #else
  2216. #ifdef USE_TERMCAP
  2217.          "with termcap database",
  2218. #else
  2219.          "with unknown terminal database",
  2220. #endif /* USE_TERMCAP */
  2221. #endif /* SLANG_TERMINFO */
  2222. #else
  2223.         : "using some unknown curses library",
  2224. #endif /* HAVE_SLANG */
  2225. #endif /* HAVE_X */
  2226.         status_using_old_tools ? " and compiled with old tools" : "");
  2227.  
  2228.     if (print_last_wd)
  2229.     write (stdout_fd, ".", 1);
  2230. }
  2231.  
  2232. #ifdef _OS_NT
  2233. #define CONTROL_FILE "\\mc.%d.control"
  2234. #else
  2235. #define CONTROL_FILE "/tmp/mc.%d.control"
  2236. #endif
  2237. char control_file [sizeof (CONTROL_FILE) + 8];
  2238. char *shell;
  2239.  
  2240. static void handle_args (int argc, char *argv [])
  2241. {
  2242.     extern int optind;
  2243.     extern char *optarg;
  2244.     int    c;
  2245.     char   *termvalue;
  2246.  
  2247. #ifdef HAVE_SLANG
  2248. #    ifdef _OS_NT
  2249.        static
  2250. #    else
  2251.        extern
  2252. #    endif
  2253. int SLtt_try_termcap;
  2254. #endif
  2255.  
  2256. #ifdef USE_TERMCAP
  2257.     SLtt_try_termcap = 1;
  2258. #endif
  2259.     
  2260.     while ((c = getopt (argc, argv, "VbsdPcfC:hmxtuUv:l:NX")) != -1){
  2261.     switch (c){
  2262.     case 'V':
  2263.         version ();
  2264.         exit (1);
  2265.         
  2266.     case 'b':
  2267.         disable_colors = 1;
  2268.         break;
  2269.  
  2270.     case 'c':
  2271.         disable_colors = 0;
  2272. #ifdef HAVE_SLANG
  2273.         force_colors = 1;
  2274. #endif
  2275.         break;
  2276.  
  2277.     case 'f':
  2278.         fprintf (stderr, "Library directory for the Midnight Commander: " LIBDIR "\n");
  2279.         exit (1);
  2280.         
  2281.     case 'm':
  2282.         use_8th_bit_as_meta = 0;
  2283.         break;
  2284.         
  2285.         
  2286.     case 'v':
  2287.         view_one_file = optarg;
  2288.         break;
  2289.  
  2290. #ifdef USE_NETCODE
  2291.     case 'l':
  2292.         ftpfs_set_debug (optarg);
  2293.         break;
  2294. #endif
  2295.     case 'P':
  2296.         print_last_wd = 1;
  2297.         break;
  2298.         
  2299.     case 's':
  2300.         slow_terminal = 1;
  2301.         break;
  2302.  
  2303.     case 'd':
  2304.         use_mouse_p = NO_MOUSE;
  2305.         break;
  2306.  
  2307.     case 'C':
  2308.         command_line_colors = optarg;
  2309.         break;
  2310.  
  2311.     case 'x':
  2312.         force_xterm = 1;
  2313.         break;
  2314.  
  2315. #ifdef HAVE_SLANG
  2316.     case 't':
  2317.         SLtt_try_termcap = 1;
  2318.         break;
  2319.         
  2320.     case 'N':
  2321.         SLtt_want_unicode ();
  2322.         break;
  2323. #endif
  2324.         
  2325.     case 'u':
  2326. #ifdef HAVE_SUBSHELL_SUPPORT
  2327.         use_subshell = 0;
  2328. #endif
  2329.         break;
  2330.  
  2331.     case 'X':
  2332. #ifdef HAVE_SUBSHELL_SUPPORT
  2333.         debug_subshell = 1;
  2334. #endif
  2335.         break;
  2336.         
  2337.     case 'U':
  2338. #ifdef HAVE_SUBSHELL_SUPPORT
  2339.         use_subshell = 1;
  2340. #endif
  2341.         break;
  2342.         
  2343.     case '?':
  2344.     case 'h':
  2345.     default:
  2346.         version ();
  2347.         fprintf (stderr, "Usage is:\n"
  2348.             "mc [-bCcdfhPsuUlVv?] [other_panel_dir]\n"
  2349.             "-b Force black and white\n"
  2350.             "-C <keyword>=<fore>,<back> Color usage\n"
  2351.             "   keywords: normal, selected, marked, markselect, "
  2352.                         "errors, reverse,\n"
  2353.             "   dnormal, dfocus, dhotnormal, dhotfocus,\n"
  2354.             "   menu, menuhot, menusel, menuhotsel\n"
  2355.             "   colors: black, red, green, brightgreen, brown,\n"
  2356.                     "   yellow, blue, brightblue, magenta, brightmagenta,\n"
  2357.                     "   cyan, brightcyan, lightgray and white\n"
  2358.             "-c Force color, only available if terminfo allows it\n"
  2359.             "-d Disable mouse support\n"
  2360.             "-f Print configured paths\n"
  2361.             "-m Don't use the highest character bit as meta flag\n"
  2362.             "-P At exit, print last working directory\n"
  2363.             "-s Disables verbose operation (for slow terminals)\n"
  2364. #ifdef HAVE_SLANG
  2365.             "-t Activate support for the TERMCAP variable\n"
  2366.             "-N Use Unicode if available\n"
  2367. #endif
  2368. #ifdef USE_NETCODE
  2369.             "-l file Log ftpfs commands to the file\n"
  2370. #endif
  2371.             "-u Disable the concurrent subshell mode\n"
  2372.             "-U Force the concurrent subshell mode\n"
  2373.             "-v [file] start up into the viewer mode\n"
  2374.                     "-x Force xterm mouse support and screen save/restore\n"
  2375.             );
  2376.         exit (1);
  2377.     }
  2378.     }
  2379. #ifdef _OS_NT
  2380.     SetConsoleTitle ("GNU Midnight Commander");
  2381.     if (!shell || !*shell)
  2382.     shell = "cmd.exe";
  2383.      /* Default opening mode for files is binary, not text (CR/LF translation) */
  2384.     _fmode = _O_BINARY;
  2385. #else
  2386.     termvalue = getenv ("TERM");
  2387.     if (!termvalue){
  2388.     fprintf (stderr, "The TERM environment variable is unset!\n");
  2389.     termvalue = "";
  2390.     }
  2391.     if (force_xterm || strncmp (termvalue, "xterm", 5) == 0){
  2392.     use_mouse_p = XTERM_MOUSE;
  2393.     xterm_flag = 1;
  2394. #    ifdef SET_TITLE
  2395.     printf ("\33]0;GNU Midnight Commander\7");
  2396. #    endif
  2397.     }
  2398.     shell = getenv ("SHELL");
  2399.     if (!shell || !*shell)
  2400.     shell = strdup (getpwuid (geteuid ()) -> pw_shell);
  2401.     if (!shell || !*shell)
  2402.     shell = "/bin/sh";
  2403. #endif /* _OS_NT */
  2404.     
  2405.     sprintf (control_file, CONTROL_FILE, getpid ());
  2406.     my_putenv ("MC_CONTROL_FILE", control_file);
  2407.  
  2408.     /* sets the current dir and the other dir */
  2409.     for (; optind < argc; optind++){
  2410.     if (this_dir){
  2411.         other_dir = strdup (argv [optind]);
  2412.     } else {
  2413.         char buffer [MC_MAXPATHLEN+2];
  2414.         
  2415.         this_dir = argv [optind];
  2416.         mc_get_current_wd (buffer, sizeof (buffer)-2);
  2417.     }
  2418.     }
  2419. }
  2420.  
  2421. static void sigchld_handler_no_subshell (int sig)
  2422. {
  2423. #ifndef _OS_NT
  2424.     int pid, status;
  2425.  
  2426.     if (!console_flag)
  2427.     return;
  2428.     
  2429.     /* COMMENT: if it were true that after the call to handle_console(..INIT)
  2430.        the value of console_flag never changed, we could simply not install
  2431.        this handler at all if (!console_flag && !use_subshell). */
  2432.  
  2433.     /* That comment is no longer true.  We need to wait() on a sigchld
  2434.        handler (that's at least what the tarfs code expects currently). */
  2435.  
  2436.     pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
  2437.     
  2438.     if (pid == cons_saver_pid){
  2439.     /* {{{ Someone has stopped or killed cons.saver; restart it */
  2440.  
  2441.     if (WIFSTOPPED (status))
  2442.         kill (pid, SIGCONT);
  2443.     else
  2444.     {
  2445.         handle_console (CONSOLE_DONE);
  2446.         handle_console (CONSOLE_INIT);
  2447.     }
  2448.     /* }}} */
  2449.     }
  2450.  
  2451.     /* If we get here, some other child exited; ignore it */
  2452. #endif /* OS_NT */
  2453. }
  2454.  
  2455. void init_sigchld (void)
  2456. {
  2457.     struct sigaction sigchld_action;
  2458.  
  2459.     sigchld_action.sa_handler =
  2460. #ifdef HAVE_SUBSHELL_SUPPORT
  2461.     use_subshell ? sigchld_handler :
  2462. #endif
  2463.     sigchld_handler_no_subshell;
  2464.  
  2465.     sigemptyset (&sigchld_action.sa_mask);
  2466.  
  2467. #ifdef SA_RESTART
  2468.         sigchld_action.sa_flags = SA_RESTART;
  2469. #else
  2470.         sigchld_action.sa_flags = 0;
  2471. #endif
  2472.  
  2473.     sigaction (SIGCHLD, &sigchld_action, NULL);
  2474. }    
  2475.  
  2476. int main (int argc, char *argv [])
  2477. {
  2478. #ifndef _OS_NT
  2479.     /* Backward compatibility: Gives up privileges in case someone
  2480.        installed the mc as setuid */
  2481.     setuid (getuid ());
  2482. #endif
  2483.     vfs_init ();
  2484.  
  2485. #ifdef HAVE_X
  2486.     /* NOTE: This call has to be before any our argument handling :) */
  2487.     if (xtoolkit_init (&argc, argv) == -1)
  2488.     exit (1);
  2489. #endif
  2490. #ifdef HAVE_SLANG
  2491.     SLtt_Ignore_Beep = 1;
  2492. #endif
  2493.  
  2494.     /* NOTE: This has to be called before slang_init or whatever routine
  2495.        calls any define_sequence */
  2496.     init_key ();
  2497.     
  2498.     handle_args (argc, argv);
  2499.     
  2500.     /* Used to report the last working directory at program end */
  2501.     if (print_last_wd){
  2502. #ifndef _OS_NT    
  2503.     stdout_fd = dup (1);
  2504.     close (1);
  2505.     if (open (ttyname (0), O_RDWR) < 0)
  2506.         if (open ("/dev/tty", O_RDWR) < 0) {
  2507.         /* Try if stderr is not redirected as the last chance */
  2508.             char *p = strdup (ttyname (0));
  2509.             
  2510.             if (!strcmp (p, ttyname (2)))
  2511.                 dup2 (2, 1);
  2512.             else {
  2513.                 fprintf (stderr,
  2514.                          "Couldn't open tty line. You have to run mc without the -P flag.\n"
  2515.                  "On some systems you may want to run # `which mc`\n");
  2516.             exit (1);
  2517.             }
  2518.             free (p);
  2519.         }
  2520. #endif
  2521.     }
  2522.  
  2523. #   ifdef HAVE_X
  2524.     /* This is to avoid subshell trying to restard any child pid
  2525.      * that happends to have cons_saver_pid (a random startup value).
  2526.      * and PID 1 is init, unlikely we could be the parent of it.
  2527.      */
  2528.     cons_saver_pid = 1;
  2529. #   else
  2530.     /* Must be done before installing the SIGCHLD handler [[FIXME]] */
  2531.     handle_console (CONSOLE_INIT);
  2532. #   endif
  2533.     
  2534. #   ifdef HAVE_SUBSHELL_SUPPORT
  2535.     subshell_get_console_attributes ();
  2536. #   endif
  2537.     
  2538.     /* Install the SIGCHLD handler; must be done before init_subshell() */
  2539.     init_sigchld ();
  2540.     
  2541.     /* This variable is used by the subshell */
  2542. #ifdef _OS_NT
  2543.     home_dir = copy_strings (getenv ("HOMEDRIVE"), getenv ("HOMEPATH"));
  2544. #else
  2545.     home_dir = getenv ("HOME");
  2546. #endif
  2547.     home_dir = home_dir ? home_dir : PATH_SEP_STR;
  2548.  
  2549. #   ifdef HAVE_X
  2550.     /* We need this, since ncurses endwin () doesn't restore the signals */
  2551.     save_stop_handler ();
  2552. #   endif
  2553.  
  2554.     /* Must be done before init_subshell, to set up the terminal size: */
  2555.     /* FIXME: Should be removed and LINES and COLS computed on subshell */
  2556.     slang_init ();
  2557.     initscr ();
  2558.  
  2559. #   ifdef HAVE_SUBSHELL_SUPPORT
  2560.     /* Done here to ensure that the subshell doesn't  */
  2561.     /* inherit the file descriptors opened below, etc */
  2562.  
  2563.     if (use_subshell)
  2564.         init_subshell ();  
  2565. #   endif
  2566.  
  2567.     load_setup ();
  2568.  
  2569.     init_curses ();
  2570. #   ifndef HAVE_X
  2571.     /* Removing this from the X code let's us type C-c */
  2572.     load_key_defs ();
  2573.  
  2574.     /* Also done after init_subshell, to save any shell init file messages */
  2575.     if (console_flag)
  2576.     handle_console (CONSOLE_SAVE);
  2577.     if (alternate_plus_minus && (console_flag || xterm_flag)) {
  2578.         fprintf (stderr, "\033="); fflush (stderr);
  2579.     }
  2580. #   endif
  2581.  
  2582. #   ifdef HAVE_SUBSHELL_SUPPORT
  2583.     if (use_subshell){
  2584.         prompt = strip_ctrl_codes (subshell_prompt);
  2585.         if (!prompt)
  2586.         prompt = "";
  2587.     } else
  2588. #   endif
  2589.         prompt = (geteuid () == 0) ? "# " : "$ ";
  2590.  
  2591.     /* Program main loop */
  2592.     do_nc ();
  2593.     
  2594.     /* Virtual File System shutdown */
  2595.     vfs_shut ();
  2596.  
  2597. #   ifndef HAVE_X
  2598.     /* Miguel, maybe the fix in slang is not required and
  2599.      * it could be done by removing the slang_done_screen.
  2600.      * Do I need to call slang_reset_tty then?
  2601.      */
  2602.     endwin ();
  2603.     slang_shutdown ();
  2604.  
  2605.     if (console_flag && quit != SUBSHELL_EXIT)
  2606.     restore_console ();
  2607.     if (alternate_plus_minus && (console_flag || xterm_flag)) {
  2608.         fprintf (stderr, "\033>"); fflush (stderr);
  2609.     }
  2610. #   endif
  2611.  
  2612. #ifndef _OS_NT
  2613.     signal (SIGCHLD, SIG_DFL);  /* Disable the SIGCHLD handler */
  2614. #endif
  2615.     
  2616. #   ifndef HAVE_X
  2617.     if (console_flag)
  2618.     handle_console (CONSOLE_DONE);
  2619. #   endif
  2620.     putchar ('\r');  /* Hack to make shell's prompt start at left of screen */
  2621.  
  2622. #ifdef _OS_NT
  2623.     /* On NT, home_dir is malloced */
  2624.     free (home_dir);
  2625. #endif
  2626.     if (print_last_wd) {
  2627.         if (print_last_revert)
  2628.             write (stdout_fd, ".", 1);
  2629.         else
  2630.         write (stdout_fd, last_wd_string, strlen (last_wd_string));
  2631.     free (last_wd_string);
  2632.     }
  2633.  
  2634. #ifdef HAVE_MAD
  2635.     done_key ();
  2636. #endif
  2637.     mad_finalize (__FILE__, __LINE__);
  2638. #ifdef HAVE_X
  2639.     xtoolkit_end ();
  2640. #endif
  2641.     return 0;
  2642. }
  2643.